﻿#include "UdpBroadcast.h"
#include <QDebug>
#include "jsoncpp-1.9.1/json/json.h"

UdpBroadcast *UdpBroadcast::Singleton()
{
    static UdpBroadcast * singleton = new UdpBroadcast();
    return singleton;
}

UdpBroadcast::UdpBroadcast(QObject *parent) : QObject(parent)
{
    pudpClientSocket = new QUdpSocket();
    QUdpSocket::connect(pudpClientSocket, &QUdpSocket::readyRead, this, &UdpBroadcast::slotClientReadyRead);
}

UdpBroadcast::~UdpBroadcast()
{
    if(pudpClientSocket)
    {
        delete pudpClientSocket;
        pudpClientSocket = nullptr;
    }
    this->pudpServerSocketVec.clear();
}

bool UdpBroadcast::InitClient(QVector<quint16> serverPortVec)
{
    this->clientServerPortVec = serverPortVec;
    return true;
}

bool UdpBroadcast::InitServer(QString serverName, QString serverAddr, QVector<quint16> serverPort)
{
    this->serverPortVec = serverPort;
    this->serverName = serverName;
    this->serverAddr = serverAddr;
    this->pudpServerSocketVec.clear();

    for(int i = 0; i < this->serverPortVec.size(); ++i)
    {
        QSharedPointer<QUdpSocket> pSocket(new QUdpSocket());
        QUdpSocket::connect(pSocket.get(), &QUdpSocket::readyRead, this, &UdpBroadcast::slotServerReadyRead);
        if(!pSocket->bind(this->serverPortVec[i], QUdpSocket::ShareAddress))
        {
            continue;
        }
        this->pudpServerSocketVec.append(pSocket);
        return true;
    }
    qDebug() << "InitServer failed. " << serverName << ", " << serverAddr << ", " << serverPort;
    return false;
}

void UdpBroadcast::scan()
{
    QByteArray datagram = "helloWebServer";
    for (auto it : this->clientServerPortVec)
    {
        pudpClientSocket->writeDatagram(datagram, QHostAddress::Broadcast, it);
    }
}

void UdpBroadcast::slotClientReadyRead()
{
    if(!pudpClientSocket)
    {
        return ;
    }
    while (pudpClientSocket->hasPendingDatagrams())
    {
        QHostAddress peerAddress;
        quint16 peerPort = 0;
        QString peerName;

        QByteArray datagram;
        datagram.resize(int(pudpClientSocket->pendingDatagramSize()));
        pudpClientSocket->readDatagram(datagram.data(), datagram.size(), &peerAddress, &peerPort);
        /*
            qDebug() << "peerName:" << peerName
                     << ", peerAddress:" << peerAddress
                     << ", peerPort:" << peerPort
                     << " ### " << "Received datagram: " << datagram.constData();
        */

        /*QHostInfo::lookupHost(peerAddress.toString(), [](QHostInfo info) {
                qDebug() << "lookupHost::peerName:" << info.hostName()
                            << ", peerAddress:" << info.addresses()
                            ;
            });*/


        std::string strMsgUtf8 = datagram.toStdString();
        Json::Value root;
#if 1
        Json::CharReaderBuilder rbuilder;
        std::unique_ptr<Json::CharReader> const reader(rbuilder.newCharReader());
        std::string errs;
        if(!reader->parse(strMsgUtf8.data(), strMsgUtf8.data() + strMsgUtf8.size(), &root, &errs))
        {// json解析
            qDebug() << "json parse failed. json:" << datagram;
            return;
        }
#else
        Json::Reader reader;
        if (!reader.parse(strMsgUtf8, root))
        {// json解析
            qDebug() << "json parse failed. json:" << datagram;
            return;
        }
#endif
        auto funcGetJsonString = [](Json::Value& node, const std::string strNodeName, QString& strVal)->bool{
            if (!node.isMember(strNodeName))
            {
                qDebug() << tr("json %1 isn't exist").arg(QString::fromStdString(strNodeName));
                return false;
            }
            if (node[strNodeName].isNull())
            {
                qDebug() << tr("json %1 isn't exist").arg(QString::fromStdString(strNodeName));
                return false;
            }
            if (!node[strNodeName].isString())
            {
                qDebug() << tr("json %1 isn't string value").arg(QString::fromStdString(strNodeName));
                return false;
            }
            strVal = QString::fromUtf8(node[strNodeName].asString().c_str());
            return true;
        };

        QString serverName;
        if(!funcGetJsonString(root, "serverName", serverName))
        {
            continue;
        }

        QString serverAddr;
        if(!funcGetJsonString(root, "serverAddr", serverAddr))
        {
            continue;
        }

        // 发送信号
        signalNewServer(serverName, serverAddr);

    }
}

void UdpBroadcast::slotServerReadyRead()
{
    QUdpSocket * pudpServerSocket = qobject_cast<QUdpSocket *>(sender());
    if(!pudpServerSocket)
    {
        qDebug() << "slotServerReadyRead():pudpServerSocket is null";
        return ;
    }
    while (pudpServerSocket->hasPendingDatagrams())
    {
        QHostAddress peerAddress;
        quint16 peerPort = 0;
        //QString peerName;

        /*QString localDomainName = QHostInfo::localDomainName();
                    QString localHostName = QHostInfo::localHostName();
                    qDebug() << "localDomainName:" << localDomainName
                        << ", localHostName:" << localHostName
                        ;*/
        /*QHostInfo::lookupHost(peerAddress.toString(), [](QHostInfo info) {
                        qDebug() << "lookupHost::peerName:" << info.hostName();
                    });*/

        QByteArray datagram;
        datagram.resize(int(pudpServerSocket->pendingDatagramSize()));
        pudpServerSocket->readDatagram(datagram.data(), datagram.size(), &peerAddress, &peerPort);

        /*qDebug() << "peerName:" << peerName
                        << ", peerAddress:" << peerAddress
                        << ", peerPort:" << peerPort
                        << " ### " << tr("Received datagram: ***%1***").arg(datagram.constData());*/



        if (QString::fromUtf8(datagram) == "helloWebServer")
        {// 返回数据

            Json::Value root;
            root["serverName"] = serverName.toUtf8().toStdString();
            root["serverAddr"] = serverAddr.toUtf8().toStdString();

            Json::StreamWriterBuilder wbuilder;
            //wbuilder["commentStyle"] = "None";
            wbuilder["indentation"] = "";
            std::string document = Json::writeString(wbuilder, root);
            qDebug() << QString::fromStdString(document);
            pudpServerSocket->writeDatagram(document.data(), static_cast<qint64>(document.size()), peerAddress, peerPort);

            //QString strSendData = tr("{\"serverName\":\"%1\", \"serverAddr\":\"%2\"}").arg(serverName).arg(serverAddr);
            //QByteArray sendDataBytes = strSendData.toUtf8();
            //pudpServerSocket->writeDatagram(sendDataBytes, peerAddress, peerPort);
        }
    }
}




